/**
 * @file executionObj.c
 * @brief Contiene le implementazioni delle funzioni utilizzate per gestire gli
 * oggetti necessari per l'esecuzione dei comandi: Richieste e Comandi.
 *
 * Sono presenti le funzioni per inizializzare delle richieste e dei comandi. Viene
 * definito un comando di default nel caso il processo non riesca a individuare il comando
 * digitato dall'utente.
 *
 * @date Mar 24, 2012
 * @author Francesco Corvino
 */
#include "executionObj.h"
#include "../logproxy/logproxy.h"
#include "../CHandler/applicationLib.h"

/**
 * @brief Inizializza la struttura dati UserRequest ricavando gli attributi
 * principali dalla linea (stringa ricavata dall'input) immessa dall'utente.
 */
void UserRequest_init(UserRequest * req, char* linereq){
	// inizializza la linea d'invocazione
	int sizes = strlen(linereq) +1;
	if((req->linereq=malloc(sizes))!=NULL){
		strcpy(req->linereq,linereq);
	}
	// assegna il nome del comando
	int posch = UserParam_getFirstPos(linereq, " ?\n") + 1; // ricava termine comando
	if((req->nameCmd = malloc(posch))!=NULL){ // alloca la memoria necessaria
		strncpy(req->nameCmd,linereq,posch);  // copia la stringa del comando + ch successivo
		req->nameCmd[posch-1] = '\0';		  // sostituisce il ch successivo con NULL
	}
	// parserizza i parametri
	DynArray_init(&(req->params),UserParam_cmp,sizeof(UserParam));
	char * paramsLine = linereq + posch;
	UserParam_fillArrDef(&(req->params), paramsLine);
	log_namedlevel(REQUEST_NAMEDLOG,LOG_DEBUG_LEVEL,"Creata una richiesta con cmd:<%s> numparam:%d",
			req->nameCmd, req->params.numelement);
}

/**
 * @brief Elimina gli spazi di memoria allocati per una richiesta.
 */
void UserRequest_destroy(UserRequest * req){
	DynArray_destroy(&(req->params));
	free(req->linereq);
	free(req->nameCmd);
}

/**
 * @brief Funzione utilizzata per confrontare due richieste.
 *
 * Si confrontano in base alla chiave della sessione associata.
 */
int UserRequest_cmpBySession(const void * a, const void * b){
	if(a==NULL && b==NULL) return 0;
	UserRequest *A, *B;
	if(a!=NULL) A = (UserRequest*) a; else return -1;
	if(b!=NULL)	B = (UserRequest*) b; else return 1;
	int ka = A->session->keySession;
	int kb = B->session->keySession;
	return (ka>kb)?1:((ka==kb)?0:-1);
}

void* Command_helpInterpV1(void * value, void * context){
	/// - Controlla se è stato fornito un contesto
	if(context!=NULL) {
		/// controlla se è richiesta la versione
		if(strcmp(context,"version")) return (void*) "1.0";
	}
	/// se non è espicitato nessun particolare contesto ritorna il valore assegnato a value
	return value;
}

void Command_initBySimpleDef(InterfaceCommand *cmd, SimpleDescCommand *scmd){
	Command_initSimple(cmd, scmd->namecmd,scmd->execfnc);
	HiddenType_init(&(cmd->descriptorInfo),scmd->helpstr,strlen(scmd->helpstr) + 1);
	cmd->descriptorInfo.interpretfnc = Command_helpInterpV1;
}

/** @brief Funzione di creazione dei comandi.
 *
 * Permette di definire tramite i parametri passatti tutte le specifiche di un comando
 * rappresentato dalla struttura DescCommand.
 *
 * @param tmp puntatore al comando da inizializzare
 * @param name stringa del nome da assegnare.
 * @param info permette di fornire delle informazioni sul comando.
 * @param type descrive il tipo di comando e ne specifica il comportamento.
 * @param execute puntatore a funzione che specifica il codice da eseguire su invocazione del comando.
 *
 * @see Command_initSimple() versione semplificata.
 */
void Command_initComplete(InterfaceCommand * tmp, char* name,
		void (*execute)(), HiddenType *info, HiddenType *type ){
	// implementata i valory base del comando
	Command_initSimple(tmp,name,execute);
	// assegna gli altri valori al comando
	if(info!=NULL) memcpy(&(tmp->descriptorInfo),info,sizeof(HiddenType));
	if(type!=NULL) memcpy(&(tmp->typeCommand),type, sizeof(HiddenType));
}

/**
 * @brief Funzione di utilità per la definizione dei comandi.
 *
 * Permette di inizializzare con i valori strettamente necessari una specifica di comando.
 *
 * @return restituisce un puntatore a una struttura descrittiva di un comando da utilizzare per registrarlo.
 *
 * @see Command_initComplete() versione completa dell'inizializzazione.
 * @see envFat_registerCMD() funzione utilizzata per registrare i comandi.
 */
void Command_initSimple(InterfaceCommand* tmp, char* name, void (*execute)()){
	log_namedlevel(COMMAND_NAMEDLOG,LOG_INFO_LEVEL,"definizione di un nuovo comando: <%s>",name);
	if(tmp!=NULL){
		if((tmp->name = malloc(strlen(name)+1))!=NULL) strcpy(tmp->name, name);
		tmp->execute = execute;
	} else {
		log_namedlevel(COMMAND_NAMEDLOG,LOG_ERROR_LEVEL,"memoria non allocata per: <%s>",name);
	}
}

/**
 * @brief implementazione di un comando semplice.
 */
void _Command_simple(){
	AppLib_writeToHost("Comando non registrato!\n");
}

InterfaceCommand * Command_getDefault(){
//	return Command_initSimple("default",_Command_simple);
	InterfaceCommand *tmp = malloc(sizeof(InterfaceCommand));
	Command_initSimple(tmp,"default",_Command_simple);
	return tmp;
}

/**
 * @brief esegue le operazini di liberazione della memoria per la struttura di un comando.
 *
 * @param cmdelem puntatore all'elemento da eliminare.
 */
void Command_destroy(const void * cmdelem){
	InterfaceCommand * delCmd = (InterfaceCommand*) cmdelem;
	free(delCmd->name);
	delCmd->name =NULL;
}

/**
 * @brief Funzione utilizzata per confrontrare due Comandi per nome.
 */
int Command_cmp(const void * a,const void * b){
	char *A=NULL, *B=NULL;
	if((a==NULL) && (b==NULL)) return 0;
	if(a!=NULL) A = ((InterfaceCommand*) a)->name; else return -1;
	if(b!=NULL) B = ((InterfaceCommand*) b)->name; else return 1;
	return strcmp(A, B);
}

/**
 * @brief Funzione che permettere la ricerca di comandi in un'array.
 *
 * @param name Nome del comando da cercare.
 * @param commands array di comandi in cui cercare.
 */
InterfaceCommand * Command_get(DynArray *commands, char *name){
	log_namedlevel(COMMAND_NAMEDLOG, LOG_DEBUG_LEVEL,
			"Avvio le ricerche del comando: <%s> su un totale di %d elementi",
			name, commands->numelement);
	InterfaceCommand cmpElem;Command_initSimple(&cmpElem,name,NULL);
	void *tmp = DynArray_get(commands,&cmpElem);
	Command_destroy(&cmpElem);
	if(tmp==NULL) return NULL;
	return (InterfaceCommand*) tmp;
}
